/********************************************************/
/*	Author:		gong_libin			*/
/*	Date:		2014_08_13			*/
/*	File:		GtRmUnix.c			*/
/********************************************************/

#include "GtGlobal.h"
#include <unistd.h>
#include <sys/un.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <netinet/ip.h>
#define __FAVOR_BSD
#include <netinet/udp.h>
#include <netinet/tcp.h>
#include <net/ethernet.h>

void GtRuHttp(UCHAR* puszRecv, int iLength);
void GtRuGtpu(UCHAR* puszRecv, int iLength);
void GtRuGtpc(UCHAR* puszRecv, int iLength);
void GtRuRads(UCHAR* puszRecv, int iLength);
void GtRuPrint(UCHAR* puszRecv, int iLength);
int GtRuNetwork(UCHAR* puszRecv, int iLength);

int main(int argc, char* argv[])
{
	int iOn = 1;
	int iPort = 0;
	int iSocket = 0;
	int iLength = 0;
	int iOffset = 0;
	int iSize = 0x00100000;
	struct sockaddr_un stAddr;
	UCHAR uszRecv[GT_KBYTES8] = { 0 };
	int iAddr = sizeof(struct sockaddr_un);
	char* pszPath = (char*)"/tmp/GtDcpTest.sock";

	if (NULL != argv[1]) {
		pszPath = argv[1];
	}

	unlink(pszPath);
	memset(&stAddr, '\0', sizeof(stAddr));

	if (GT_FAILURE != (iSocket = socket(AF_UNIX, SOCK_DGRAM, 0))) {
		setsockopt(iSocket, SOL_SOCKET, SO_RCVBUF, &iSize, sizeof(iSize));
		setsockopt(iSocket, SOL_SOCKET, SO_REUSEADDR, &iOn, sizeof(iOn));

		stAddr.sun_family = AF_UNIX;
		memcpy(stAddr.sun_path, pszPath, strlen(pszPath));

		bind(iSocket, (struct sockaddr*)&stAddr, iAddr);
		while ((iLength = recvfrom(iSocket, uszRecv, GT_KBYTES8, 0, (struct sockaddr*)&stAddr, (socklen_t*)&iAddr)) > 0) {
			if ((iOffset = GtRuNetwork(uszRecv, iLength)) > 0) {
				switch (iPort) {
					case 1813:
						GtRuRads(uszRecv + iOffset, iLength - iOffset);
						break;
					case 2152:
						GtRuGtpu(uszRecv + iOffset, iLength - iOffset);
						break;
					case 2123:
						GtRuGtpc(uszRecv + iOffset, iLength - iOffset);
						break;
					default:
						GtRuHttp(uszRecv + iOffset, iLength - iOffset);
						break;
				}
			}
			memset(uszRecv, '\0', GT_KBYTES8);
		}

		close(iSocket);
	}

	return GT_SUCCESS;
}

int GtRuNetwork(UCHAR* puszRecv, int iLength)
{
	int iSize = 0;
	struct ip* pstIP = NULL;
	struct udphdr* pstUdp = NULL;
	struct tcphdr* pstTcp = NULL;

	GT_PRINT("\nPacket: %d\n", iLength);

	/* ip */
	pstIP = (struct ip*)puszRecv;
	GT_PRINT("SrcAddr: %s\t", (char*)inet_ntoa(pstIP->ip_src));
	GT_PRINT("DstAddr: %s\n", (char*)inet_ntoa(pstIP->ip_dst));
	iSize = pstIP->ip_hl * 4;

	switch (pstIP->ip_p) {
		case IPPROTO_TCP:
			pstTcp = (struct tcphdr*)((UCHAR*)pstIP + pstIP->ip_hl * 4);
			GT_PRINT("SrcPort: %d\t", ntohs(pstTcp->th_sport));
			GT_PRINT("DstPort: %d\n", ntohs(pstTcp->th_dport));
			iSize += pstTcp->th_off * 4;
			break;
		case IPPROTO_UDP:
			pstUdp = (struct udphdr*)((UCHAR*)pstIP + pstIP->ip_hl * 4);
			GT_PRINT("SrcPort: %d\t", ntohs(pstUdp->uh_sport));
			GT_PRINT("DstPort: %d\n", ntohs(pstUdp->uh_dport));
			iSize += sizeof(struct udphdr);
			break;
		default:
			break;
	}

	return iSize;
}

void GtRuPrint(UCHAR* puszRecv, int iLength)
{
	int iCount = 0;

	GT_PRINT("Packet[%d]:", iLength);
	for (; iCount < iLength; iCount ++) {
		if (0 == iCount % sizeof(int)) {
			if (0 == iCount % (sizeof(int) * 2)) {
				GT_PRINT("\n");
			}
			else {
				GT_PRINT(" ");
			}
		}
		GT_PRINT("0x%02x ", *(puszRecv + iCount));
	}
	GT_PRINT("\n");

	return;
}

void GtRuHeader(UCHAR* puszRecv, int iLength)
{
	GT_PRINT("Flag: 0x%02x\t", *puszRecv ++);

	GT_PRINT("Version: 0x%02x\t", *puszRecv >> 4);
	GT_PRINT("Protocol: 0x%02x\t", (*puszRecv & 0x0f) >> 3);
	GT_PRINT("Wide: 0x%02x\t", (*puszRecv & 0x07) >> 2);
	GT_PRINT("Response: 0x%02x\t", (*puszRecv & 0x03) >> 1);
	GT_PRINT("Expand: 0x%02x\n", *puszRecv ++ & 0x01);

	GT_PRINT("Type: 0x%02x\t", *puszRecv ++);
	GT_PRINT("Verb: 0x%02x\t", *puszRecv ++);
	GT_PRINT("Attr: 0x%02x\t", *puszRecv ++);
	GT_PRINT("Result: 0x%02x\t", *puszRecv ++);

	GT_PRINT("Total: %d\t", ntohs(*(USHORT*)puszRecv));
	GT_PRINT("Length: %d\n", ntohl(*(int*)(puszRecv + sizeof(USHORT))));

	return;
}

void GtRuHttp(UCHAR* puszRecv, int iLength)
{
	GT_PRINT("%s", (char*)puszRecv);

	return;
}

void GtRuGtpu(UCHAR* puszRecv, int iLength)
{
	GtRuPrint(puszRecv, iLength);

	return;
}

void GtRuGtpc(UCHAR* puszRecv, int iLength)
{
	GtRuPrint(puszRecv, iLength);

	return;
}

void GtRuRads(UCHAR* puszRecv, int iLength)
{
	GtRuPrint(puszRecv, iLength);

	return;
}
